import dialog from './dialog'
import getData from '../data/get'

// 标记 “快照列表”
let marks = []

// 翻译按钮 “快照列表”
let buttons = []

/**
 * 节点是否被标记
 * @param {element} node 
 * @returns {boolean}
 */
function includeMark(node) {
    for (let index = 0; index < marks.length; index++) {
        let str = marks[index].str
        if (
            (node.innerText && node.innerText.indexOf(str) !== -1) || // 标识在innerText中
            (node.title && node.title.indexOf(str) !== -1) || // 标识在title属性中
            (node.placeholder && node.placeholder.indexOf(str) !== -1) // 标识在placeholder属性中
        ) {
            return true
        }
    }
    return false
}

/**
 * 查询所有节点（递归遍历DOM节点）
 * @param {element} node 遍历节点
 */
function searchNodes(node) {
    const nodes = []
    function fun(node) {
        for (let index = 0; index < node.children.length; index++) {
            const n = node.children[index]
            if (n.children.length) {
                fun(n, nodes)
                // 子元素不含标记，则标记的是自己
                if (includeMark(n) && childIncludeMark(n.children) == false) {
                    nodes.push(n)
                }
            } else if (includeMark(n)) {
                nodes.push(n)
            }
        }
    }
    fun(node)
    return nodes
}

/**
 * 查询子元素是否包含标记
 * @param {element[]} children 子节点列表
 * @returns 
 */
function childIncludeMark(children) {
    for (let index = 0; index < children.length; index++) {
        if (includeMark(children[index])) return true
    }
    return false
}

/**
 * 更新元素节点
 * @param {element} node 更新节点
 * @param {string} value 设置值
 */
function updateElement(node, value) {
    if (node.innerText) node.innerText = value
    if (node.title) node.setAttribute('title', value)
    if (node.placeholder) node.setAttribute('placeholder', value)
}

/**
 * 添加操作元素
 * @param {element} node 挂载节点
 * @param {object} options 配置
 */
function addHandleElement(node, options) {
    // 翻译按钮
    const button = document.createElement("button")
    button.innerText = options.title

    // 放置按钮（自身相对父级位置）
    button.style.position = 'absolute'
    button.style.zIndex = options.zIndex
    button.style.top = node.offsetTop + 'px'
    button.style.left = node.offsetLeft + 'px'
    button.style.opacity = 0
    if (node.offsetParent) node.offsetParent.appendChild(button)

    // 根据窗口（自身相对窗口位置）
    // const top = getTop(node)
    // const left = getLeft(node)
    // button.style.position = 'fixed'
    // document.body.appendChild(button)

    // 翻译事件（鼠标点击事件）
    button.addEventListener('click', (event) => {
        // 阻止冒泡事件、默认事件
        if (event.stopPropagation) event.stopPropagation()
        if (event.preventDefault) event.preventDefault()

        // 弹出输入框
        if (node.mark) dialog(options, node.mark.key, node.mark.base, (res) => {
            // 更新当前状态
            if (options.code == res.language) updateElement(node, res.value)
        })
    })

    // 鼠标移入事件
    button.addEventListener('mouseenter', () => { button.style.opacity = 1 })

    // 鼠标移出事件
    button.addEventListener('mouseleave', () => { button.style.opacity = 0 })

    // 缓存按钮
    buttons.push(button)

    // 监听元素位置变化，按钮随之变化
    const observer = new MutationObserver(() => {
        button.style.top = node.offsetTop + 'px'
        button.style.left = node.offsetLeft + 'px'
    })
    // 以上述配置开始观察目标节点
    observer.observe(node, { attributes: true, attributeFilter: ['style'], attributeOldValue: true })
}

/**
 * 节点元素上挂载标记信息
 * @param {element} node 挂载节点
 */
function nodeAddMark(node) {
    // 获取value
    let value = node.innerText || node.title || node.placeholder
    // 获取key,base
    const mark = marks.find(item => item.value == value.trim())
    // 挂载标记
    if (mark) node.mark = mark
}

/**
 * 获取所有标记节点
 */
function getNodeAll() {
    const nodes = []
    function fun(node) {
        for (let index = 0; index < node.children.length; index++) {
            const n = node.children[index]
            if (n.children.length) fun(n)
            else if (n.mark) nodes.push(n)
        }
    }
    fun(document.body)
    return nodes
}

/**
 * 解析所有节点（转义）
 * @param {element[]} nodes 节点列表
 * @param {object} options 配置
 */
function explainNodes(nodes, options) {
    nodes.forEach(node => {
        if (options.mark === null) return

        // 移除标记
        const removeMark = (str) => (str ? str.replaceAll(options.mark, '') : str)

        // 还原数据
        updateElement(node, removeMark(node.innerText || node.title || node.placeholder))

        // 挂载标记信息
        nodeAddMark(node)
        // 添加操作元素
        // addHandleElement(node, options)
    })

    // 还原数据后位置会重新更新，所以延迟执行
    setTimeout(() => {
        nodes.forEach(node => {
            // 添加操作元素
            if (options.mark) addHandleElement(node, options)
        })
    }, 500)
}

//获取元素的纵坐标（相对于窗口）
function getTop(e) {
    var offset = e.offsetTop;
    if (e.offsetParent != null) offset += getTop(e.offsetParent);
    return offset;
}

//获取元素的横坐标（相对于窗口）
function getLeft(e) {
    var offset = e.offsetLeft;
    if (e.offsetParent != null) offset += getLeft(e.offsetParent);
    return offset;
}

// 记录标记
export function recordMark(str, key, value, base) {
    const include = marks.some(item => item.str == str && item.key == key && item.value == value)
    if (include == false) marks.push({ str, key, value, base })
}

/**
 * 查找标记
 * @param {object} options 配置
 */
export function searchMarks(options) {
    // buttons = []

    // 查询节点
    const nodes = searchNodes(document)
    // 解析节点
    explainNodes(nodes, options)

    // console.log('执行检索', nodes)
}

/**
 * 切换语言
 * @param {object} options 配置
 */
export function changeLang(options) {
    getNodeAll().forEach(node => {
        let mark = node.mark
        if (mark) {
            let value = getData(options.code, mark.key) || mark.base
            updateElement(node, value)
        }
    })
}

/**
 * 改变翻译状态
 * @param {boolean} status 翻译状态
 */
export function changeStatus(status) {
    buttons.forEach(btn => {
        btn.style.display = status ? 'block' : 'none'
    })
}

/**
 * 监听文档变化
 * @param {object} options 配置
 */
export function documentChange(options) {
    let timer = null
    // 创建一个观察器实例并传入回调函数
    const observer = new MutationObserver((mutationsList, observer) => {
        clearTimeout(timer)
        timer = setTimeout(() => searchMarks(options), 500)
    })
    // 以上述配置开始观察目标节点
    observer.observe(document, { attributes: true, childList: true, subtree: true })
    // 之后，可停止观察
    // observer.disconnect()
}
